package com.me.data;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.provider.CalendarContract.Events;
import android.provider.CalendarContract.Instances;

import com.me.db.CalendarManager;
import com.me.db.CalendarQuery;
import com.me.db.MeDbManager;
import com.me.db.MeQuery;
import com.me.util.AppConstant;
import com.me.util.AppUtil;

public class DataService {

	private CalendarManager calendarManager;
	private MeDbManager meDbManager;

	public DataService(ContentResolver contentResolver, Context context) {

		calendarManager = new CalendarManager(contentResolver);
		meDbManager = new MeDbManager(context);

	}
	
	
// ***************************************************************************************************************
// Retrieve Records
	
	public ArrayList<MeEvent> retrievePendingEvent() {

		Cursor cursor = meDbManager.fetchEvents();

		long id = -1;
		String title;
		int allDay;
		long start;
		long end;
		String venue;
		ArrayList<MeEvent> eventList = new ArrayList<MeEvent>();

		while (cursor.moveToNext()) {
			id = cursor.getLong(MeQuery.INDEX_EVENT_ID);
			title = cursor.getString(MeQuery.INDEX_EVENT_TITLE);
			allDay = cursor.getInt(MeQuery.INDEX_EVENT_ALL_DAY);
			start = cursor.getLong(MeQuery.INDEX_EVENT_START);
			end = cursor.getLong(MeQuery.INDEX_EVENT_END);
			venue = cursor.getString(MeQuery.INDEX_EVENT_VENUE);

			Calendar cal = Calendar.getInstance();
			cal.setTimeInMillis(start);

			MeEvent event = new MeEvent(id, title, allDay, start, end, venue);
			eventList.add(event);
		}
		return eventList;
	}

	public ArrayList<MeEvent> retrieveCalendarEvent(int position) {
		Calendar calStart = Calendar.getInstance();
		Calendar calEnd = Calendar.getInstance();

		calStart.set(Calendar.DAY_OF_MONTH, 1);
		calStart.set(Calendar.HOUR_OF_DAY, 0);
		calStart.set(Calendar.MINUTE, 0);
		calStart.set(Calendar.SECOND, 0);

		calStart.add(Calendar.MONTH, position - 12);

		calEnd.set(Calendar.DAY_OF_MONTH, 1);
		calEnd.set(Calendar.HOUR_OF_DAY, 0);
		calEnd.set(Calendar.MINUTE, 0);
		calEnd.set(Calendar.SECOND, 0);

		calEnd.add(Calendar.MONTH, position - 11);
		calEnd.add(Calendar.MINUTE, -1);

		Cursor cursor = calendarManager.fetchInstance(
				calStart.getTimeInMillis(), calEnd.getTimeInMillis());

		return getEventsByMonth(calStart.get(Calendar.MONTH), cursor);
	}
	
	public ArrayList<DBItem> retrieveTitles() {

		Cursor cursor = meDbManager.fetchTitles();
		long id;
		String prefix;
		String name;
		int count;
		ArrayList<DBItem> titleList = new ArrayList<DBItem>();

		while (cursor.moveToNext()) {
			id = cursor.getLong(MeQuery.INDEX_TITLE_ID);
			prefix = cursor.getString(MeQuery.INDEX_TITLE_PREFIX);
			name = cursor.getString(MeQuery.INDEX_TITLE_NAME);
			count = cursor.getInt(MeQuery.INDEX_TITLE_COUNT);
			titleList.add(new DBItem(id, prefix, name, count));
		}
		
		return titleList;
	}

	public ArrayList<DBItem> retrieveLoactions() {

		Cursor cursor = meDbManager.fetchLocations();
		long id;
		String prefix;
		String name;
		int count;

		ArrayList<DBItem> locationList = new ArrayList<DBItem>();

		while (cursor.moveToNext()) {
			id = cursor.getLong(MeQuery.INDEX_LOCATION_ID);
			prefix = cursor.getString(MeQuery.INDEX_LOCATION_PREFIX);
			name = cursor.getString(MeQuery.INDEX_LOCATION_NAME);
			count = cursor.getInt(MeQuery.INDEX_TITLE_COUNT);
			locationList.add(new DBItem(id, prefix, name, count));
		}
		return locationList;
	}
	
	public ArrayList<String> getAllTitles() {

		Cursor cursor = meDbManager.getTitleNames();

		ArrayList<String> titleList = new ArrayList<String>();

		while (cursor.moveToNext()) {
			titleList.add(cursor.getString(0));
		}
		
		return titleList;
	}

	public ArrayList<String> getAllLocation() {

		Cursor cursor = meDbManager.getLoactionNames();

		ArrayList<String> locationList = new ArrayList<String>();

		while (cursor.moveToNext()) {
			locationList.add(cursor.getString(0));;
		}
		return locationList;
	}
	
// Retrieve Records
// ***************************************************************************************************************
// Format Records
	
	public ArrayList<MeEvent> getEvents(Cursor cursor) {

		long id = -1;
		String title;
		int allDay;
		long start;
		long end;
		String venue;
		ArrayList<MeEvent> eventList = new ArrayList<MeEvent>();

		while (cursor.moveToNext()) {

			id = cursor.getLong(CalendarQuery.Instance.INDEX_EVENT_ID);
			title = cursor.getString(CalendarQuery.Instance.INDEX_EVENT_TITLE);
			allDay = cursor.getInt(CalendarQuery.Instance.INDEX_EVENT_ALL_DAY);
			start = cursor.getLong(CalendarQuery.Instance.INDEX_EVENT_START);
			end = cursor.getLong(CalendarQuery.Instance.INDEX_EVENT_END);
			venue = cursor
					.getString(CalendarQuery.Instance.INDEX_EVENT_LOCATION);

			Calendar cal = Calendar.getInstance();
			cal.setTimeInMillis(start);

			MeEvent event = new MeEvent(id, title, allDay, start, end, venue);
			eventList.add(event);
		}

		return eventList;
	}
	
	public ArrayList<MeEvent> getEventsByMonth(int month, Cursor cursor) {

		long id;
		String title;
		int allDay;
		long start;
		long end;
		String venue;
		ArrayList<MeEvent> eventList = new ArrayList<MeEvent>();

		while (cursor.moveToNext()) {

			id = cursor.getLong(CalendarQuery.Instance.INDEX_EVENT_ID);
			title = cursor.getString(CalendarQuery.Instance.INDEX_EVENT_TITLE);
			allDay = cursor.getInt(CalendarQuery.Instance.INDEX_EVENT_ALL_DAY);
			start = cursor.getLong(CalendarQuery.Instance.INDEX_EVENT_START);
			end = cursor.getLong(CalendarQuery.Instance.INDEX_EVENT_END);
			venue = cursor
					.getString(CalendarQuery.Instance.INDEX_EVENT_LOCATION);

			Calendar cal = Calendar.getInstance();
			cal.setTimeInMillis(start);

			if (month != -1 && cal.get(Calendar.MONTH) != month) {
				continue;
			}

			MeEvent event = new MeEvent(id, title, allDay, start, end, venue);
			eventList.add(event);
		}
		return eventList;
	}
	
	
	
// Format Records
// ***************************************************************************************************************
// Insert single record 	
	
	public void insertOneEvent(String inputEventTitle, String inputEventVenue,
			int allDay, long inputEventStart, long inputEventEnd) {
		meDbManager.insertOneEvent(inputEventTitle, inputEventVenue, allDay,
				inputEventStart, inputEventEnd);

		// test
		meDbManager.inserOneTitle(inputEventTitle);
		meDbManager.inserOneLocation(inputEventVenue);
	}

	public void insertOneCalendarEvent(String inputEventTitle,
			String inputEventVenue, int allDay, long inputEventStart,
			long inputEventEnd) {
		calendarManager.insertOneEvent(inputEventTitle, inputEventVenue,
				allDay, inputEventStart, inputEventEnd);

		// test
		meDbManager.inserOneTitle(inputEventTitle);
		meDbManager.inserOneLocation(inputEventVenue);
	}
	
	
// Insert single record
// ***************************************************************************************************************
// Insert records 	
	
	public void insertEvents(ArrayList<MeEvent> eventList) {
		meDbManager.insertEvents(eventList);
	}

	public void insertCalendarEvents(ArrayList<MeEvent> eventList) {
		calendarManager.insertEvents(eventList);
	}

	public void insertDBItems(ArrayList<MeEvent> eventList) {
		ArrayList<String> titles = new ArrayList<String>();
		ArrayList<String> locations = new ArrayList<String>();

		for (int i = 0; i < eventList.size(); i++) {
			MeEvent event = eventList.get(i);
			String title = event.getTitle();
			String venue = event.getVenue();

			if (title != null && title.length() > 0)
				titles.add(title);

			if (venue != null && venue.length() > 0)
				locations.add(venue);
		}

		meDbManager.insertTitles(titles);
		meDbManager.insertLocations(locations);
	}

// Insert records
// ***************************************************************************************************************
// Delete records 
	
	public int deleteEvents(int eventType, String[] eventIDs) {
		StringBuffer inClauseBuffer = new StringBuffer();
		inClauseBuffer.append("(");
		for (int i = 1; i < eventIDs.length; i++) { // 1 less than size
			inClauseBuffer.append("?,");
		}
		inClauseBuffer.append("?)");
		String inClause = inClauseBuffer.toString();

		switch (eventType) {
		case AppConstant.EVENT_INDEX_PENDING:
			return meDbManager.deleteEvents(inClause, eventIDs);
		case AppConstant.EVENT_INDEX_CALENDAR:
			return calendarManager.deleteEvents(inClause, eventIDs);
		}

		return -1;
	}

	public int deleteItems(int eventType, String[] itemIDs) {
		StringBuffer inClauseBuffer = new StringBuffer();
		inClauseBuffer.append("(");
		for (int i = 1; i < itemIDs.length; i++) { // 1 less than size
			inClauseBuffer.append("?,");
		}
		inClauseBuffer.append("?)");
		String inClause = inClauseBuffer.toString();

		switch (eventType) {
		case AppConstant.EVENT_INDEX_TITLE:
			return meDbManager.deleteTitles(inClause, itemIDs);
		case AppConstant.EVENT_INDEX_LOCATION:
			return meDbManager.deleteLocations(inClause, itemIDs);
		}

		return -1;
	}

// Delete records
// ***************************************************************************************************************
// Search records

	public ArrayList<MeEvent> searchEvents(String type, String keyword) {

		Calendar calStart = Calendar.getInstance();
		Calendar calEnd = Calendar.getInstance();

		calStart.set(Calendar.DAY_OF_MONTH, 1);
		calStart.set(Calendar.HOUR_OF_DAY, 0);
		calStart.set(Calendar.MINUTE, 0);
		calStart.set(Calendar.SECOND, 0);

		calStart.add(Calendar.MONTH, -12); // temp

		calEnd.set(Calendar.DAY_OF_MONTH, 1);
		calEnd.set(Calendar.HOUR_OF_DAY, 0);
		calEnd.set(Calendar.MINUTE, 0);
		calEnd.set(Calendar.SECOND, 0);

		calEnd.add(Calendar.MONTH, 12); // temp
		calEnd.add(Calendar.MINUTE, -1);

		ArrayList<MeEvent> eventList = new ArrayList<MeEvent>();
		Cursor cursor = null;
		if (type.equals("title")) {
			cursor = calendarManager.searchCalendarEvents(
					calStart.getTimeInMillis(), calEnd.getTimeInMillis(),
					Instances.TITLE, keyword);
			eventList.addAll(getEvents(cursor));

			cursor = meDbManager.searchEvents(Events.TITLE, keyword);
			eventList.addAll(getEvents(cursor));
		} else if (type.equals("location")) {
			cursor = calendarManager.searchCalendarEvents(
					calStart.getTimeInMillis(), calEnd.getTimeInMillis(),
					Instances.EVENT_LOCATION, keyword);
			eventList.addAll(getEvents(cursor));

			cursor = meDbManager.searchEvents(Events.EVENT_LOCATION, keyword);
			eventList.addAll(getEvents(cursor));
		}

		return eventList;
	}


	public ArrayList<String> searchTitles(String[] tokens) {
		
		ArrayList<String> prefixes = new ArrayList<String>();

		for (int i=0; i < tokens.length; i++) {
			if (tokens[i].length()>2) {
				prefixes.add(tokens[i].substring(0,1).toUpperCase());
			}

		}

		ArrayList<String> itemList = new ArrayList<String>();

		if (prefixes.size() > 0) {

			Cursor cursor = meDbManager.searchTitles(prefixes.toArray(new String[prefixes.size()]));

			if (cursor != null) {
				while (cursor.moveToNext()) {
					itemList.add(cursor.getString(0));
				}
			}
		}
		return itemList;
	}

	public ArrayList<String> searchLocations(String[] tokens) {
		
		ArrayList<String> prefixes = new ArrayList<String>();

		for (int i=0; i < tokens.length; i++) {
			if (tokens[i].length()>2) {
				prefixes.add(tokens[i].substring(0,1).toUpperCase());
			}

		}

		ArrayList<String> itemList = new ArrayList<String>();

		if (prefixes.size() > 0) {

			Cursor cursor = meDbManager.searchLocations(prefixes.toArray(new String[prefixes.size()]));

			if (cursor != null) {
				while (cursor.moveToNext()) {
					itemList.add(cursor.getString(0));
				}
			}
		}
		return itemList;
	}	
	
	
	public ArrayList<String> searchTitlesWhenTyping(String prefix) {
		
		ArrayList<String> titleList = new ArrayList<String>();

		Cursor cursor =  meDbManager.searchTitles(new String[]{ prefix.toUpperCase() });

		if (cursor != null) {
			while (cursor.moveToNext()) {
				titleList.add(cursor.getString(0));
			}
		}
		
		return titleList;
	}
	
	public ArrayList<String> searchLocationsWhenTyping(String prefix) {
		
		ArrayList<String> locationList = new ArrayList<String>();

		Cursor cursor =  meDbManager.searchTitles(new String[]{ prefix.toUpperCase() });

		if (cursor != null) {
			while (cursor.moveToNext()) {
				locationList.add(cursor.getString(0));
			}
		}
		
		return locationList;
	}
	
// Search Records
// ***************************************************************************************************************
// Others
	
	public void updateEvent(String eventID, String inputEventTitle,
			String inputEventVenue, int allDay, long inputEventStart, long inputEventEnd) {
		
		meDbManager.updateEvent(eventID, inputEventTitle, inputEventVenue,
				allDay, inputEventStart, inputEventEnd);
	}
			
}